home *** CD-ROM | disk | FTP | other *** search
Text File | 1996-04-04 | 17.7 KB | 653 lines | [TEXT/KAHL] |
- /***************************************************** IMPLEMENTATION
- DATE: 10/24/93
- AUTHOR: Eric R. Rosé
-
- CLASS: CPPVisualTree
-
- SUPERCLASS: CPPTree
-
- This C++ class handles the display of a tree by combining
- CPPVisualObject with CPPTree
-
- ********************************************************************/
-
- #include <CPPWindow.h>
- #include <CPPVisualTree.h>
- #include <CPPVisualTreeNode.h>
- #include <Commands.h>
- #include <stdlib.h>
- #include <ToolboxTools.h>
-
- extern Rect kEmptyRect;
-
- /*-----------------------------------------------------------------*/
- /*------------------------ APPLY ROUTINES -------------------------*/
- /*-----------------------------------------------------------------*/
-
- void SetSelectState (CPPTreeNode *theNode, long param)
- /* set the selection state of the node according to the value */
- /* passed in param; cause a redraw of the node */
- {
- if (theNode)
- ((CPPVisualTreeNode *)theNode)->SetSelect((short)param, FALSE, TRUE);
- }
-
- /*-----------------------------------------------------------------*/
-
- void DrawOrEraseJoin (CPPTreeNode *theNode, long param)
- /* draw or erase the join leading from the node's parent to the */
- /* node; param is a boolean; if TRUE, draw, else erase */
- {
- CPPVisualTreeNode *thisNode = (CPPVisualTreeNode *)theNode;
- CPPVisualTreeNode *parentNode = (theNode) ? (CPPVisualTreeNode *)theNode->Parent : NULL;
- Rect emptyRect = {0,0,0,0};
-
- if (thisNode->notYetPlaced || (parentNode == NULL) || parentNode->notYetPlaced) return;
-
- if ((Boolean)param)
- ((CPPVisualTreeNode *)theNode)->DrawJoin (parentNode, thisNode);
- else
- ((CPPVisualTreeNode *)theNode)->EraseJoin (parentNode, thisNode);
- }
-
- /*-----------------------------------------------------------------*/
-
- void BuildSelectedList (CPPTreeNode *theNode, long param)
- /* if the passed node is selected, add it to a list passsed in param */
- {
- CPPObjectList *theList = (CPPObjectList *)param;
-
- if (theNode && ((CPPVisualTreeNode *)theNode)->IsSelected())
- theList->AppendItem(theNode);
- }
-
- /*-----------------------------------------------------------------*/
- /*------------------------ PUBLIC METHODS -------------------------*/
- /*-----------------------------------------------------------------*/
-
- void CPPVisualTree::DrawAllJoins (Boolean doDraw)
- /* cause all of the joins in the tree to be drawn or erased */
- {
- ApplyToFamily (this->topNode, DrawOrEraseJoin, (long)doDraw);
- }
-
- /*-----------------------------------------------------------------*/
-
- CPPVisualTree::CPPVisualTree (WindowPtr itsWindow,
- Point newTopLeft,
- orientStyle orientation,
- justStyle justification,
- joinTypes join,
- short branchLength) :
- CPPTree ()
- {
- this->theWindow = itsWindow;
-
- this->isPrepared = FALSE;
- this->preparedBy = NULL;
- this->SavePort = NULL;
-
- this->topLeft = newTopLeft;
-
- this->orientation = orientation;
- this->justification = justification;
- this->whichJoin = join;
- this->branchLength = branchLength;
-
- this->lastClicked = NULL;
- this->lastClickTime = 0;
- this->nodeMargin = 2;
- }
-
- /*-----------------------------------------------------------------*/
-
- CPPVisualTree::~CPPVisualTree (void)
- {
-
- }
-
- /*-----------------------------------------------------------------*/
-
- Boolean CPPVisualTree::Member (char *className)
- {
- if (strcmp(className, CPPVisualTree::ClassName()) == 0)
- return TRUE;
- else
- return CPPTree::Member(className);
- }
-
- /*-----------------------------------------------------------------*/
-
- char *CPPVisualTree::ClassName (void)
- {
- return "CPPVisualTree";
- }
-
- /*-----------------------------------------------------------------*/
-
- void CPPVisualTree::Prepare (CPPObject *caller)
- /* if the grafport has not been prepared, prepare it now */
- {
- if (!isPrepared)
- {
- this->isPrepared = TRUE;
- this->preparedBy = caller;
-
- if (this->theWindow)
- {
- GetPort (&SavePort);
- SetPort (this->theWindow);
- UserSpecificPrepare();
- }
- }
- }
-
- /*-----------------------------------------------------------------*/
-
- void CPPVisualTree::Restore (CPPObject *caller)
- /* if the one who prepared us is giving us this command, restore */
- /* the prior characteristics of the grafport */
- {
- if (this->isPrepared && this->preparedBy == caller)
- {
- UserSpecificRestore();
- SetPort(SavePort);
- this->isPrepared = FALSE;
- this->preparedBy = NULL;
- }
- }
-
- /*-----------------------------------------------------------------*/
-
- void CPPVisualTree::ForceRedraw (Boolean doErase)
- /* Cause the tree to redraw itself; optionally erase it entirely */
- /* first */
- {
- if (this->topNode)
- {
- if (doErase)
- CPPTree::BroadcastMessage (kEraseFamily, (void *)TRUE);
- CPPTree::BroadcastMessage (kDrawFamily, (void *)TRUE);
- }
- }
-
- /*-----------------------------------------------------------------*/
-
- void CPPVisualTree::ForceResize (Boolean doDraw)
- /* have the entire tree recalculate its size; optionally have it */
- /* erase itself before and redraw itself after calculation */
- {
- if (this->topNode)
- {
- if (doDraw)
- CPPTree::BroadcastMessage (kEraseFamily, (void *)TRUE);
-
- CPPTree::BroadcastMessage (kResizeFamily, NULL);
-
- if (doDraw)
- CPPTree::BroadcastMessage (kDrawFamily, (void *)TRUE);
- }
- }
-
-
- /*-----------------------------------------------------------------*/
-
- void CPPVisualTree::ForceMove (Boolean doDraw, Point topLeft)
- /* have the entire tree move itself; optionally have it erase */
- /* itself before and redraw itself after calculation */
- {
- if (this->topNode)
- {
- if (doDraw)
- CPPTree::BroadcastMessage (kEraseFamily, (void *)TRUE);
-
- this->topLeft = topLeft;
- CPPTree::BroadcastMessage (kMoveFamily, (void *)(&topLeft));
-
- if (doDraw)
- CPPTree::BroadcastMessage (kDrawFamily, (void *)TRUE);
- }
- }
-
- /*-----------------------------------------------------------------*/
-
- void CPPVisualTree::GetTreeBounds (Rect *itsBounds)
- /* return the rectangle which describes the position of the tree */
- {
- Rect tempRect;
-
- if (this->topNode)
- topNode->GetFamilyBounds (itsBounds);
- else
- *itsBounds = kEmptyRect;
- }
-
- /*-----------------------------------------------------------------*/
-
- void CPPVisualTree::AdjustTree (void)
- /* This routine makes sure that the tree is pinned to the upper */
- /* left hand corner of the tree, as specified by the user */
- {
- Rect tempRect;
-
- if (this->topNode)
- topNode->GetFamilyBounds (&tempRect);
-
- if ((tempRect.left != this->topLeft.h) ||
- (tempRect.top != this->topLeft.v))
- ForceMove (TRUE, this->topLeft);
- }
-
- /*-----------------------------------------------------------------*/
-
- void CPPVisualTree::Draw (void)
- {
- this->forceDraw = TRUE;
- CPPTree::BroadcastMessage(kDrawFamily, (void *)TRUE);
- this->forceDraw = FALSE;
- }
-
- /*-----------------------------------------------------------------*/
-
- void CPPVisualTree::DrawPoint2Point (Point FromPt, Point ToPt)
- /* Draw a direct line between the two passed-in points */
- {
- MoveTo (FromPt.h, FromPt.v);
- LineTo (ToPt.h, ToPt.v);
- }
-
- /*-----------------------------------------------------------------*/
-
- void CPPVisualTree::DrawRightAngle (Point FromPt, Point ToPt,
- orientStyle orientation)
- /* Draw a right-angle join between the two passed-in points */
- {
- MoveTo (FromPt.h, FromPt.v);
-
- switch (orientation) {
- case kLeft2Right :
- case kRight2Left :
- LineTo (FromPt.h + (ToPt.h - FromPt.h) / 2, FromPt.v);
- LineTo (FromPt.h + (ToPt.h - FromPt.h) / 2, ToPt.v);
- break;
-
- case kTopDown :
- case kBottomUp:
- LineTo (FromPt.h, FromPt.v + (ToPt.v - FromPt.v) / 2);
- LineTo (ToPt.h, FromPt.v + (ToPt.v - FromPt.v) / 2);
- break;
- }
-
- LineTo (ToPt.h, ToPt.v);
- }
-
- /*-----------------------------------------------------------------*/
-
- void CPPVisualTree::DrawDefaultJoin (CPPVisualTreeNode *FromNode,
- CPPVisualTreeNode *ToNode)
- /* Use the orientation and join information to draw a join between */
- /* the two passed-in nodes */
- {
- Point FromTop, FromBottom, FromLeft, FromRight;
- Point ToTop, ToBottom, ToLeft, ToRight;
- orientStyle orient = this->orientation;
-
- FromNode->GetAnchorPoints (&FromLeft, &FromRight, &FromTop, &FromBottom);
- ToNode->GetAnchorPoints (&ToLeft, &ToRight, &ToTop, &ToBottom);
-
- switch (this->whichJoin) {
-
- case kNoJoin :
-
- break;
-
- case kPointToPoint :
- switch (orient) {
- case kLeft2Right :
- DrawPoint2Point (FromRight, ToLeft);
- break;
- case kRight2Left :
- DrawPoint2Point (FromLeft, ToRight);
- break;
- case kBottomUp:
- DrawPoint2Point (FromTop, ToBottom);
- break;
- case kTopDown :
- DrawPoint2Point (FromBottom, ToTop);
- break;
- }
- break;
-
- case kRightAngle :
- switch (orient) {
- case kLeft2Right :
- DrawRightAngle (FromRight, ToLeft, kLeft2Right);
- break;
- case kRight2Left :
- DrawRightAngle (FromLeft, ToRight, kRight2Left);
- break;
- case kTopDown :
- DrawRightAngle (FromBottom, ToTop, kTopDown);
- break;
- case kBottomUp :
- DrawRightAngle (FromTop, ToBottom, kBottomUp);
- break;
- }
- break;
- }
- }
-
- /*-----------------------------------------------------------------*/
-
- void CPPVisualTree::SetBranchLength (short newLength)
- /* Change the length of the branches of the tree */
- {
- if (this->branchLength != newLength)
- {
- this->Prepare(this);
- CPPTree::BroadcastMessage (kEraseFamily, (void *)TRUE);
- this->branchLength = newLength;
- CPPTree::BroadcastMessage (kResizeFamily, NULL);
- CPPTree::BroadcastMessage (kDrawFamily, (void *)TRUE);
- this->Restore(this);
- }
- }
-
- /*-----------------------------------------------------------------*/
-
- void CPPVisualTree::SetNodeMargin (short newMargin)
- /* change the amount of space between the tree's nodes */
- {
- if (this->nodeMargin != newMargin)
- {
- this->Prepare(this);
- CPPTree::BroadcastMessage (kEraseFamily, (void *)TRUE);
- this->nodeMargin = newMargin;
- CPPTree::BroadcastMessage (kResizeFamily, NULL);
- CPPTree::BroadcastMessage (kDrawFamily, (void *)TRUE);
- this->Restore(this);
- }
- }
-
- /*-----------------------------------------------------------------*/
-
- void CPPVisualTree::SetOrientation (orientStyle newOrient)
- /* switch the orientation of the tree from horiz to vert or vv */
- {
- if (this->orientation != newOrient)
- {
- this->Prepare(this);
- CPPTree::BroadcastMessage (kEraseFamily, (void *)TRUE);
- this->orientation = newOrient;
- CPPTree::BroadcastMessage (kResizeFamily, NULL);
- CPPTree::BroadcastMessage (kDrawFamily, (void *)TRUE);
- this->Restore(this);
- }
- }
-
- /*-----------------------------------------------------------------*/
-
- void CPPVisualTree::SetJustification (justStyle newJust)
- /* Switch the orientation to left, center, or right */
- {
- if (this->justification != newJust)
- {
- this->Prepare(this);
- CPPTree::BroadcastMessage (kEraseFamily, (void *)TRUE);
- this->justification = newJust;
- CPPTree::BroadcastMessage (kResizeFamily, NULL);
- CPPTree::BroadcastMessage (kDrawFamily, (void *)TRUE);
- this->Restore(this);
- }
- }
-
- /*-----------------------------------------------------------------*/
-
- void CPPVisualTree::SetJoinType (joinTypes newJoin)
- /* Change the join type to rightangle, none, or point2point */
- {
- if (this->whichJoin != newJoin)
- {
- this->Prepare(this);
- DrawAllJoins (FALSE);
- this->whichJoin = newJoin;
- DrawAllJoins (TRUE);
- this->Restore(this);
- }
- }
-
- /*-----------------------------------------------------------------*/
-
- void CPPVisualTree::DoCut (void)
- /* cut the currently selected nodes of the tree */
- /* SUBCLASS SHOULD OVERRIDE */
- {
- SysBeep(1);
- }
-
- /*-----------------------------------------------------------------*/
-
- void CPPVisualTree::DoCopy (void)
- /* copy the entire tree as a picture; store in the clipboard */
- {
- PicHandle tempPict = GetTreePicture (TRUE, TRUE);
- KillPicture (tempPict);
- }
-
- /*-----------------------------------------------------------------*/
-
- void CPPVisualTree::DoPaste (void)
- /* paste new data into the area */
- /* SUBCLASS SHOULD OVERRIDE */
- {
- SysBeep(1);
- }
-
- /*-----------------------------------------------------------------*/
-
- void CPPVisualTree::DoClear (void)
- /* clear the currently selected nodes of the tree */
- /* SUBCLASS SHOULD OVERRIDE */
- {
- CPPObjectList *theList = new CPPObjectList();
- CPPVisualTreeNode *theNode = NULL;
-
- if (this->topNode)
- {
- ApplyToFamily (this->topNode, BuildSelectedList, (long)theList);
-
- // delete each node in the list in turn
- for (long i = theList->GetNumItems(); i >= 1; i--)
- {
- theNode = (CPPVisualTreeNode *)((*theList)[i]);
- if (theNode)
- theNode->DeleteNode(theNode);
- }
- }
-
- delete theList;
- }
-
- /*-----------------------------------------------------------------*/
-
- void CPPVisualTree::DoSelectAll (void)
- /* select the entire tree */
- {
- if (this->topNode)
- ApplyToFamily(this->topNode, SetSelectState, kSetSelect);
- }
-
- /*-----------------------------------------------------------------*/
-
- Boolean CPPVisualTree::DoCommand (short commandID)
- /* do a command associated with a menu */
- {
- switch (commandID) {
- case kCmdCut :
- DoCut();
- break;
- case kCmdCopy :
- DoCopy();
- break;
- case kCmdPaste :
- DoPaste();
- break;
- case kCmdSelectAll :
- DoSelectAll();
- break;
- case kCmdClear :
- DoClear();
- break;
- default:
- return FALSE; // we are the first class with
- break; // the 'DoCommand' method
- }
-
- return TRUE;
- }
-
- /*-----------------------------------------------------------------*/
-
- Boolean CPPVisualTree::DoTreeClick (EventRecord *theEvent)
- {
- Point myPt = theEvent->where,
- startPt,
- endPt;
- Rect selRect;
- CPPVisualTreeNode *theNode;
- Boolean wasDoubleClick = FALSE;
- GrafPtr savePort;
-
- GetPort(&savePort);
- SetPort(this->theWindow);
-
- GlobalToLocal (&myPt);
-
- // first, check to see if the click was in a node
- if (theNode = ((CPPVisualTreeNode *)this->topNode)->PointInNode (myPt))
- {
- // determine whether we have double-clicked on the node
- wasDoubleClick = (theNode == this->lastClicked) &&
- (theEvent->when - this->lastClickTime <= GetDblTime());
- this->lastClicked = theNode;
- this->lastClickTime = theEvent->when;
-
- if (wasDoubleClick)
- theNode->DoDoubleClick (theEvent->modifiers);
- else
- { // if the shift key is down, invert selection state
- if (ShiftKeyDown(theEvent->modifiers))
- theNode->SetSelect(kToggleSelect, FALSE, TRUE);
- else
- // if the command key is down, add to selection
- if (CommandKeyDown (theEvent->modifiers))
- theNode->SetSelect(kSetSelect, FALSE, TRUE);
- else
- { // if no modifiers down, de-select all and select this one
- ApplyToFamily(this->topNode, SetSelectState, kClearSelect);
- theNode->SetSelect(kSetSelect, FALSE, TRUE);
- }
- theNode->DoSingleClick (theEvent->modifiers);
- }
- SetPort (savePort);
- return TRUE;
- }
- else // the user did not click in a node. De-select the current selection
- { // if necessary, then return FALSE
- if (!ShiftKeyDown (theEvent->modifiers) &&
- !CommandKeyDown(theEvent->modifiers))
- ApplyToFamily(this->topNode, SetSelectState, kClearSelect);
- return FALSE;
- } // PtInRect
-
- SetPort(savePort);
- return FALSE;
- }
-
- /*-----------------------------------------------------------------*/
-
- PicHandle CPPVisualTree::GetTreePicture (Boolean asQDPICT, Boolean placeInClipboard)
- /* Return a picture of the tree as either a bitmap or a */
- /* quickdraw picture */
- {
- #define SetLineWidth 182
-
- typedef PointPtr *PointHndl;
-
- PicHandle tempPict;
- Rect tempRect;
- PointHndl theWidth;
- RgnHandle OldClip, NewClip;
- long dummy;
-
- this->Prepare((CPPObject *)(1312L));
- this->GetTreeBounds (&tempRect);
-
- if (asQDPICT)
- {
- // set the clipping region to be the area of the tree
- OldClip = NewRgn();
- NewClip = NewRgn();
- GetClip (OldClip);
- RectRgn (NewClip, &tempRect);
- SetClip (NewClip);
-
- // set the line width to be 1/5 by 1/5
- tempPict = OpenPicture (&tempRect);
- theWidth = (PointHndl)(NewHandle(sizeof(Point)));
- if (theWidth)
- {
- SetPt (*theWidth, 5, 1);
- PicComment(SetLineWidth, sizeof(Point), (Handle)theWidth);
- }
- this->ForceRedraw(FALSE); // draw without erasing the old tree
- ClosePicture();
-
- // restore the old clipping region
- SetClip(OldClip);
- DisposeRgn(NewClip);
- DisposeRgn(OldClip);
- }
- else
- {
- tempPict = OpenPicture(&tempRect);
- CopyBits (&theWindow->portBits, &theWindow->portBits, &tempRect,
- &tempRect, srcCopy, NULL);
- ClosePicture();
- }
-
- this->Restore((CPPObject *)(1312L));
-
- // if asked, place a copy in the clipboard before exiting
- if (placeInClipboard)
- {
- HLock((Handle)tempPict);
- dummy = ZeroScrap();
- dummy = PutScrap (GetHandleSize((Handle)tempPict), 'PICT', (Ptr)(*tempPict));
- HUnlock((Handle)tempPict);
- }
-
- return tempPict;
- }
-
- /*-----------------------------------------------------------------*/
- /*---------------------- PROTECTED METHODS ------------------------*/
- /*-----------------------------------------------------------------*/
-
- void CPPVisualTree::UserSpecificPrepare (void)
- /* Perform any special setup of the grafport before drawing */
- /* SUBCLASS MAY OVERRIDE */
- {
-
- }
-
- /*-----------------------------------------------------------------*/
-
- void CPPVisualTree::UserSpecificRestore (void)
- /* Perform any special restoration of the grafport after drawing */
- /* SUBCLASS MAY OVERRIDE */
- {
-
- }
-
-